<!doctype html>
<html>

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <title>葡萄藤PPT</title>
    <link rel="stylesheet" href="../css/reveal/reveal.css">
    <!-- PPT主题，可以在/css/reveal/theme/中选择其他主题，目前暂时只能使用该模板 -->
    <link rel="stylesheet" href="../css/reveal/theme/ptt.css">
    <!-- syntax highlighting 代码高亮主题 -->
    <link rel="stylesheet" href="../lib/reveal/css/zenburn.css">
    <!-- 打印和PDF输出样式 -->
    <script>
        var link = document.createElement('link');
        link.rel = 'stylesheet';
        link.type = 'text/css';
        link.href = window.location.search.match(/print-pdf/gi) ? '../css/reveal/print/pdf.css' :
            '../css/reveal/print/paper.css';
        document.getElementsByTagName('head')[0].appendChild(link);
    </script>
    <style>
        p {
            text-align: left;
        }
    </style>
</head>

<body>
    <img src="../img/demo/logo.png" alt="" usemap="#pttmap" class="base-logo">
    <map name="pttmap">
        <area shape="rect" coords="0,0,276,58" href="http://www.jnshu.com" alt="" target="_blank" />
    </map>
    <div class="reveal">
        <div class="slides">

            <section>
                <h2>【JS-03】什么是有限状态机</h2>
                <h3>武汉分院</h3>
                <p style="text-align: center">分享人：黄震</p>
            </section>

            <section>
                <p style="text-align: center">1.背景介绍</p>

                <p style="text-align: center">2.知识剖析</p>

                <p style="text-align: center">3.常见问题</p>

                <p style="text-align: center">4.解决方案</p>

                <p style="text-align: center">5.编码实战</p>

                <p style="text-align: center">6.扩展思考</p>

                <p style="text-align: center">7.参考文献</p>

                <p style="text-align: center">8.更多讨论</p>
            </section>

            <section>
                <h3>1.背景介绍</h3>

            </section>

            <section>
                <p>什么是有限状态机？</p>
                <p>
                    有限状态机（Finite-state machine）是一个非常有用的模型，可以模拟世界上大部分事物。它 是一个数学模型。是一个抽象机器，在任何时候都可以处于有限数量的状态之一。响应某些外部输入， FSM可以从一个状态转换到另一个状态; 从一种状态到另一种状态的变化称为过渡。
                    状态机的行为可以在现代社会中的许多设备中观察到，这些设备根据它们呈现的事件序列执行预定的一系列行为。 例如自动售货机，当存放适当的硬币组合时分配产品，当车辆等待时改变顺序的交通灯等。
                </p>
                <p>
                    在我们前端开发中，我们可以套用有限状态机模型，将业务流程状态化，划分状态和相应的触发事件与动作，利用生命周期事件进行控制与执行
                </p>
            </section>

            <section>
                <h3>二、知识剖析</h3>
            </section>

            <section>
                <section>
                    有限状态机一般都有以下特点：
                    <br/>
                    <dd style="text-align: left">（1）可以用状态来描述事物，并且任一时刻，事物总是处于一种状态；
                        <dd style="text-align: left">（2）事物拥有的状态总数是有限的；
                            <dd style="text-align: left">（3）通过触发事物的某些行为，可以导致事物从一种状态过渡到另一种状态；
                                <dd style="text-align: left">（4）事物状态变化是有规则的，A状态可以变换到B，B可以变换到C，A却不一定能变换到C；
                                    <dd style="text-align: left">（5）同一种行为，可以将事物从多种状态变成同种状态，但是不能从同种状态变成多种状态。
                </section>

                <section>
                    <p style="text-align: left">
                        状态机由一组状态和转换组成：
                        <br> 状态 : 固体 、 液体 、 气体。
                        <br> 转换 ：融化 、汽化 、 冷凝 、 冻结。
                        <br>
                        <img src="https://raw.githubusercontent.com/jakesgordon/javascript-state-machine/master/examples/matter.png" />
                        <br>
                    </p>
                </section>

                <section>
                    <p>以上的形式可以状态机来写一下</p>
                    <p>
                        首先需要引入有限状态机库
                        <a href="https://github.com/jakesgordon/javascript-state-machine">状态机库</a>
                    </p>
                    <pre>
                        <code>
             var fsm = new StateMachine({
                init: 'solid',
                transitions: [
                  { name: 'melt',     from: 'solid',  to: 'liquid' },
                  { name: 'freeze',   from: 'liquid', to: 'solid'  },
                  { name: 'vaporize', from: 'liquid', to: 'gas'    },
                  { name: 'condense', from: 'gas',    to: 'liquid' }
                ],
                methods: {
                  onMelt:     function() { console.log('I melted')    },
                  onFreeze:   function() { console.log('I froze')     },
                  onVaporize: function() { console.log('I vaporized') },
                  onCondense: function() { console.log('I condensed') }
                }
              });
                            //方法调用
                        //1，自执行方法：
                        fsm.onMelt();
                        fsm.onFreeze();
                        fsm.onVaporize();
                        fsm.onCondense();

                        //1、触发调用方式：
                         fsm.Melt();
                         fsm.Freeze();
                         fsm.Vaporize();
                         fsm.Condense();

                        </code>
                    </pre>
                </section>

                <section>
                    <p>
                        init选项用来表示fsm对象的初始状态，
                        <br> transitions选项用来描述fsm对象所有状态的变化规则，每一种变化规则对应一种行为。
                        <br> methods方法为实例的每一种行为都添加了一个方法，调用这个方法就相当于触发对象的某种行为，当对象行为发生时，对象的状态就可以发生变化。如以上例子创建的实例将拥有如下行为方法：
                        <br> fsm.Melt() : 调用该方法，实例状态将从'solid'变为'liquid'
                        <br> fsm.Freeze() : 调用该方法，实例状态将从'liquid'变为'solid'
                        <br> fsm.Vaporize() : 调用该方法，实例状态将从'liquid'变为'gas'
                        <br> fsm.Condense() : 调用该方法，实例状态将从'gas'变为'liquid'
                    </p>
                </section>

                <section>
                    <p>在老的版本中创建一个状态机用StateMachine.create
                        <br> 初始值用initial
                        <br> 变化规则用events
                        <br> 方法用的是callbacks
                        <br> 这里需要注意引入库的版本
                    </p>
                </section>

                <section>
                    <p>
                        Javascript Finite State Machine允许为每个事件指定两个自定义方法，以Melt事件为例:
                        <br> onbeforeMelt：在Melt事件发生之前触发

                        <br> onafterMelt ：在Melt事件发生之后触发。
                        <br> 每个状态指定两个自定义方法，以solid状态为例：

                        <br> onleaveSolid ：在离开solid状态时触发
                        <br> onenterLiquid ：在进入liquid状态时触发。
                        <br>
                    </p>
                </section>

                <section>
                    <p>
                        为了在发生转换时跟踪或执行操作，有以下五个通用的生命周期事件：
                        <br> // onBeforeTransition - 在任何转换之前触发
                        <br> // onLeaveState - 离开任何状态被触发
                        <br> // onTransition - 在任何过渡期间被触发
                        <br> // onEnterState - 进入任何状态被触发 ==>onState
                        <br> // onAfterTransition - 任何转换后触发 ==>onTransition
                        <br>


                    </p>

                </section>

                <section>
                    <p>
                        辅助方法：
                        <br> // fsm.is(s) - 如果状态s是当前状态，则返回true
                        <br> // fsm.can(t) - 如果t从当前状态发生转换，则返回true
                        <br> // fsm.cannot(t) - 如果t从当前状态不能发生转换，则返回true
                        <br> // fsm.transitions() - 返回当前状态允许的转换列表
                        <br> // fsm.allTransitions() - 返回所有可能的转换的列表
                        <br> // fsm.allStates() - 返回所有可能状态的列表
                        <br> //Cancelling a Transition 取消转换
                        <br>

                    </p>
                </section>
            </section>

            <section>
                <h3>三、常见问题</h3>
            </section>

            <section>
                <p style="text-align: center">有限状态机有哪些应用场景？</p>
            </section>

            <section>
                <h3>四、解决方案</h3>
            </section>

            <section>
                <p>满足3点即可用：所需状态确定，有事件触发转变状态，总状态有限且转变有规律。</p>

                <p>页面可用有限状态机的元素较多且有规律时可用：例如：开关按钮，下拉菜单，</p>

                <p>还有任务中杀人游戏的玩家死活状态、白天黑夜状态等
                    <a href="http://kenghu.jnshu.com/k/question/257">我的坑乎回答</a>
                </p>
            </section>

            <section>
                <h3>五、编码实战</h3>
            </section>

            <section>
                <h3>六、扩展思考</h3>
            </section>

            <section>
                <p style="text-align: center">有限状态机有哪些优点？</p>
            </section>

            <section>
                <p>
                    有限状态机的写法，逻辑清晰，表达力强，有利于封装事件。一个对象的状态越多、发生的事件越多，就越适合采用有限状态机的写法。 另外，JavaScript语言是一种异步操作特别多的语言，常用的解决方法是指定回调函数， 但这样会造成代码结构混乱、难以测试和除错等问题。有限状态机提供了更好的办法：
                    把异步操作与对象的状态改变挂钩，当异步操作结束的时候，发生相应的状态改变，由此再触发其他操作。 这要比回调函数、事件监听、发布/订阅等解决方案，在逻辑上更合理，更易于降低代码的复杂度。
                </p>
            </section>

            <section>
                <h3>七、参考文献</h3>
            </section>

            <section>
                <ul>
                    <li>
                        <a href="https://github.com/jakesgordon/javascript-state-machine">有限状态机库</a>
                    </li>
                    <li>
                        <a href="http://www.ruanyifeng.com/blog/2013/09/finite-state_machine_for_javascript.html">阮一峰的有限状态机</a>
                    </li>

                    <li>
                        <a href="http://blog.jobbole.com/47179/">js与有限状态机</a>
                    </li>
                </ul>
            </section>

            <section>
                <h3>八、更多讨论</h3>
            </section>

            <section>
                <h4>鸣谢</h4>

                <p style="text-align: center">感谢大家观看</p>

                <p style="text-align: center">
                    <small>BY : 蓝裕伟| 王姣妍| 黄震</small>
                </p>
            </section>

        </div>
    </div>
    <script src="../lib/reveal/js/head.min.js"></script>
    <script src="../lib/reveal/reveal.js"></script>
    <script>
        // <!--以下为常见配置属性的默认值-->
        //    <!--// {-->
        //    <!--//  controls: true, // 是否在右下角展示控制条-->
        //    <!--//  progress: true, // 是否显示演示的进度条-->
        //    <!--//  slideNumber: false, // 是否显示当前幻灯片的页数编号，也可以使用代码slideNumber: 'c / t' ，表示当前页/总页数。-->
        //    <!--//  history: false, // 是否将每个幻灯片改变加入到浏览器的历史记录中去-->
        //    <!--//  keyboard: true, // 是否启用键盘快捷键来导航-->
        //    <!--//  overview: true, // 是否启用幻灯片的概览模式，可使用"Esc"或"o"键来切换概览模式-->
        //    <!--//  center: true, // 是否将幻灯片垂直居中-->
        //    <!--//  touch: true, // 是否在触屏设备上启用触摸滑动切换-->
        //    <!--//  loop: false, // 是否循环演示-->
        //    <!--//  rtl: false, // 是否将演示的方向变成RTL，即从右往左-->
        //    <!--//  fragments: true, // 全局开启和关闭碎片。-->
        //    <!--//  autoSlide: 0, // 两个幻灯片之间自动切换的时间间隔（毫秒），当设置成 0 的时候则禁止自动切换，该值可以被幻灯片上的 ` data-autoslide` 属性覆盖-->
        //    <!--//  transition: 'default', // 切换过渡效果，有none/fade/slide/convex/concave/zoom-->
        //    <!--//  transitionSpeed: 'default', // 过渡速度，default/fast/slow-->
        //    <!--//  mouseWheel: true, //是否启用通过鼠标滚轮来切换幻灯片-->
        //    <!--// }-->
        //
        //    // 初始化幻灯片
        Reveal.initialize({
            history: true,
            dependencies: [{
                src: '../plugin/markdown/marked.js'
            }, {
                src: '../plugin/markdown/markdown.js'
            }, {
                src: '../plugin/notes/notes.js',
                async: true
            }, {
                src: '../plugin/highlight/highlight.js',
                async: true,
                callback: function () {
                    hljs.initHighlightingOnLoad();
                }
            }]
        });
        //
    </script>
</body>

</html>